/*
 * TOP SECRET Copyright 2006-2015 Transsion.com All right reserved. This software is the confidential and proprietary
 * information of Transsion.com ("Confidential Information"). You shall not disclose such Confidential Information and
 * shall use it only in accordance with the terms of the license agreement you entered into with Transsion.com.
 */
package com.yunji.framework_template.biz.crawler;

import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;

import com.yunji.framework_template.biz.cache.EhDataCache;
import com.yunji.framework_template.biz.service.NewsCrawledService;
import com.yunji.framework_template.common.constant.Constant;
import com.yunji.framework_template.common.http.HttpConnection;
import com.yunji.framework_template.common.util.ImageUtil;
import com.yunji.framework_template.common.util.MD5Util;
import com.yunji.framework_template.common.util.StringUtil;
import com.yunji.framework_template.orm.persistence.model.News;
import com.yunji.framework_template.orm.persistence.model.NewsCrawled;
import com.yunji.framework_template.orm.persistence.vo.ImageVO;
import lombok.extern.slf4j.Slf4j;

/**
 * ClassName:Crawler <br/>
 * Date: 2018年12月5日 上午11:33:51 <br/>
 * 
 * @author fenglibin1982@163.com
 * @Blog http://blog.csdn.net/fenglibing
 * @version
 * @see
 */
@Slf4j
public abstract class Crawler {

    @Autowired
    protected EhDataCache        ehDataCache;
    @Autowired
    protected NewsCrawledService newsCrawledService;
    protected TitleHandler       defaultTitleHandler = new DefaultTitleHandler();

    /**
     * 提取链接中的所有图片，多个图片地址以英文逗号"_IMG_"为分隔，<br>
     * 也可能没有取到图片的宽高，返回格式可能如下：<br>
     * http://xx/1.jpg : 只有一张图片 <br>
     * http://xx/1.jpg_IMG_http://xx/2.jpg : 两张图片 <br>
     * 
     * @param aElement 链接的A标签
     * @return 图片链接的URL和图片大小
     */
    public String getAllImagesFromHrefElement(Element aElement) {
        String imgUrls = null;
        Elements imgElements = aElement.select("img");
        if (imgElements.size() > 0) {
            for (int i = 0; i < imgElements.size(); i++) {
                Element imgElement = imgElements.get(i);
                String imgUrl = getImageFromImageElement(imgElement);
                if (!StringUtil.isEmpty(imgUrl)) {
                    if (imgUrls == null) {
                        imgUrls = Constant.EMPTY_STRING;
                    }
                    imgUrls += imgUrl;
                    imgUrls += Constant.IMG_SPLIT;
                }
            }
            if (!StringUtil.isEmpty(imgUrls) && imgUrls.endsWith(Constant.IMG_SPLIT)) {// 取掉最后的逗号
                imgUrls = imgUrls.substring(0, imgUrls.length() - Constant.IMG_SPLIT.length());
            }
        }
        return imgUrls;
    }

    /**
     * 从图片标签中提取图片的地址
     * 
     * @param imgElement
     * @return
     */
    public String getImageFromImageElement(Element imgElement) {
        return ImageUtil.getImageFromImageElement(imgElement);
    }

    /**
     * 获取当前新闻中的图片列表，以及对应图片的宽、高及图片MD5值
     * 
     * @param news
     */
    public List<ImageVO> getNewsImageList(News news) {
        List<ImageVO> imageList = new ArrayList<ImageVO>();
        String imgUrls = news.getImg();
        if (StringUtil.isEmpty(imgUrls)) {
            return imageList;
        }
        try {
            String[] imgArr = imgUrls.split(Constant.IMG_SPLIT);
            for (String imgUrl : imgArr) {
                if (StringUtil.isEmpty(imgUrl)) {
                    continue;
                }
                ImageVO imageVO = ImageVO.builder().url(imgUrl).build();
                BufferedImage bi = HttpConnection.readRemoteImage(imgUrl);
                if (bi != null) {
                    if (bi.getWidth() >= 100) {// 宽度太小的图片不要，有可能是取错了
                        imageVO.setWidth(bi.getWidth());
                        imageVO.setHeight(bi.getHeight());
                        imageVO.setImgMd5(MD5Util.md5Hex(ImageUtil.readByteFromBufferedImage(bi)));
                    }
                }
                imageList.add(imageVO);
            }
            return imageList;
        } catch (Exception e) {
            log.error("getNewsImageList exception happened:" + e.getMessage(), e);
        }
        return null;
    }

    /**
     * 增加图片的宽高属性
     * 
     * @param news 当前的新闻
     * @param imageList 缩略图信息列表
     */
    public void addImageWidthHeight(News news, List<ImageVO> imageList) {
        if (imageList == null || imageList.size() == 0) {
            return;
        }
        String imgUrls = Constant.EMPTY_STRING;
        for (ImageVO imageVO : imageList) {
            if (StringUtil.isEmpty(imageVO.getUrl())) {
                continue;
            }
            imgUrls += imageVO.getUrl();
            if (imageVO.getWidth() != null && imageVO.getWidth() > 0 && imageVO.getHeight() != null
                && imageVO.getHeight() > 0) {
                imgUrls += "(" + imageVO.getWidth() + ":" + imageVO.getHeight() + ")";
            }
            imgUrls += Constant.IMG_SPLIT;
        }
        if (!StringUtil.isEmpty(imgUrls) && imgUrls.endsWith(Constant.IMG_SPLIT)) {// 去掉最后的分隔串
            imgUrls = imgUrls.substring(0, imgUrls.length() - Constant.IMG_SPLIT.length());
        }
        news.setImg(imgUrls);
    }

    /**
     * 判断图片列表中第一张图片MD5值，是否已经存在于已经抓取的内容中，如果存在则表示该图片代表的新闻已经抓取过了，反之表示没有抓取过
     * 
     * @param imageVOList
     * @return
     */
    public boolean checkImageMd5Exists(List<ImageVO> imageVOList) {
        if (imageVOList == null || imageVOList.size() == 0) {
            return false;
        }
        try {
            /** 校验第一张图片的MD5值是不是已经存在了 **/
            ImageVO imageVO = imageVOList.get(0);
            // 对第一张图片图片进行处理校验
            if (!StringUtil.isEmpty(imageVO.getImgMd5())) {
                // 从缓存中判断
                if (ehDataCache.get(imageVO.getImgMd5()) != null) {// 该图片的MD5值已经存在，则说明当前新闻已经存在，放充对当前新闻的处理
                    return true;
                }
                NewsCrawled newsCrawled = new NewsCrawled();
                newsCrawled.setImgMd5(imageVO.getImgMd5());
                // 从数据库中判断
                List<NewsCrawled> newsCrawledList = newsCrawledService.selectByCondition(newsCrawled);
                if (newsCrawledList != null && newsCrawledList.size() > 0) {// 已经存在相同图片的MD5值
                    addMd5Cache(imageVO.getImgMd5());
                    return true;
                }
            }
        } catch (Exception e) {
            log.error("checkImageMd5Exists exception happened:" + e.getMessage(), e);
        }
        return false;
    }

    /**
     * 将对应的MD5值放到缓存中
     * 
     * @param md5
     */
    public void addMd5Cache(String md5) {
        addMd5Cache(md5, null);
    }

    /**
     * 将对应的MD5值和新闻放到缓存中
     */
    public void addMd5Cache(String md5, News news) {
        ehDataCache.put(md5, 1);
        if (news != null && news.getId() != null && news.getId() > 0) {
            // 后续使用
            ehDataCache.put(String.valueOf(news.getId()), news);
        }
    }
}
